//
//  VKApi.m
//  VKChat
//
//  Created by Максим Бризинский on 14.01.11.
//  Copyright 2011 БГУИР. All rights reserved.
//

#import "VKApi.h"
#import "MD5.h"
#import "SBJsonParser.h"
#import "User.h"


@implementation VKApi
@synthesize session = _session;
@synthesize receiverMessagesDelegate = _receiverMessagesDelegate;
@synthesize rosterDelegate = _rosterDelegate;

#pragma mark -
#pragma mark Singletone Pattern
+(VKApi*)getInstance {
	//если объект уже где-то создавался то возвращаем ранее созданный объект
	if (_instance != nil)
		return _instance;
	else {
		//иначе создаем наш объект
		_instance = [[VKApi alloc] init];
		return _instance;
	}
}

#pragma mark -
#pragma mark VK API Methods
#pragma mark Friends Methods

-(NSArray*)getAllFriends {
	//генерируем нашу MD5 подпись полученную с помощью контенации строк в алфавитном порядке (смотерть документацию VK апи)
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmethod=friends.getv=3.0%@",_session.mid,_session.secret];
	
	//применяем алгоритм MD5 для получения хеша
	sig = [MD5 md5WithString:sig];
	
	//формируем нашу строку с запросом к серверу с запросом списка uid друзей находящихся онлайн
	NSString* bodyString = [NSString stringWithFormat:@"api_id=1951595&method=friends.get&sig=%@&v=3.0&format=JSON&sid=%@",sig,_session.sid];
	
	//на основе bodyString делаем запрос который потом передадим серверу
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	
	//отправка серверу синхронного запроса (получаем ответ в NSData)
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	
	//преобразуем полученную двоичную информацию в строку ответа JSON
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	//NSLog(@"%@",jsonString);
	
	//если в строке фигурирует слово error значит возникла ошибка позднее расширим этот обработчик
	NSRange errorTest = [jsonString rangeOfString:@"error"];
	if (errorTest.location != NSNotFound) {
		NSLog(@"VKapi: getAllFriends error : %@",jsonString);
		return nil;
	} else {
		
		//если все нормально разбираем полученный ответ
		SBJsonParser* parser = [[SBJsonParser alloc] init];
		NSDictionary *dict = [parser objectWithString:jsonString];
		[parser release];
		
		//получаем значение для ключа "response" в данном случае это будет массив uid-ов
		NSArray* uids = [dict objectForKey:@"response"];
		
		//запрашиваем для всех uids анкеты (имя фамилия ссылка на фото) и получаем массив объектов User
		NSArray* users = [self getProfilesForUids:uids];
		
		return users;
	}
}

/* возвращает список анкет друзей онлайн */
-(NSArray*)getFriendsOnline {
	
	//генерируем нашу MD5 подпись полученную с помощью контенации строк в алфавитном порядке (смотерть документацию VK апи)
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmethod=friends.getOnlinev=3.0%@",_session.mid,_session.secret];
	
	//применяем алгоритм MD5 для получения хеша
	sig = [MD5 md5WithString:sig];
	
	//формируем нашу строку с запросом к серверу с запросом списка uid друзей находящихся онлайн
	NSString* bodyString = [NSString stringWithFormat:@"api_id=1951595&method=friends.getOnline&sig=%@&v=3.0&format=JSON&sid=%@",sig,_session.sid];
	
	//на основе bodyString делаем запрос который потом передадим серверу
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	
	//отправка серверу синхронного запроса (получаем ответ в NSData)
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	
	//преобразуем полученную двоичную информацию в строку ответа JSON
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	//NSLog(@"%@",jsonString);
	
	//[data release];
	//[request release];
	//[requestUrl release];
	//[urlString release];
	//[sig release];
	
	//если в строке фигурирует слово error значит возникла ошибка позднее расширим этот обработчик
	NSRange errorTest = [jsonString rangeOfString:@"error"];
	if (errorTest.location != NSNotFound) {
		NSLog(@"VKApi: getFriendsOnline error: %@",jsonString);
		return nil;
	} else {
		
		//если все нормально разбираем полученный ответ
		SBJsonParser* parser = [[SBJsonParser alloc] init];
		NSDictionary *dict = [parser objectWithString:jsonString];
		[parser release];
		
		//получаем значение для ключа "response" в данном случае это будет массив uid-ов
		NSArray* uids = [dict objectForKey:@"response"];
		
		//запрашиваем для всех uids анкеты (имя фамилия ссылка на фото) и получаем массив объектов User
		NSArray* users = [self getProfilesForUids:uids];

		return users;
	}
}

/* Получение списка анкет по uid-ам пользователя */
-(NSArray*)getProfilesForUids:(NSArray*)uids {
	
	//формируем начальные куски строк для нашей подписи (sig) и запроса (urlString) поскольку не известно какое количество анкет мы будем запрашивать
	NSMutableString *sig = [NSMutableString stringWithFormat:@"%dapi_id=1951595fields=first_name,last_name,photo_mediumformat=JSONmethod=getProfilesuids=",_session.mid]; 
	NSMutableString* bodyString = [NSMutableString stringWithFormat:@"api_id=1951595&method=getProfiles&uids="];
	
	//добовляем в наш запрос и подпись через запятую uid-ы из переданного массива
	for (NSString* uid in uids) {
		[sig appendFormat:@"%@,",uid];
		[bodyString appendFormat:@"%@,",uid];
	}
	
	//в итоге получем последним символом лишнюю запятую, удаляем ее в подписи
	NSRange lastSymbol;
	lastSymbol.location = ([sig length] - 1);
	lastSymbol.length = 1;
	[sig deleteCharactersInRange:lastSymbol];
	
	//удаляем ее в запросе
	lastSymbol.location = ([bodyString length] - 1);
	[bodyString deleteCharactersInRange:lastSymbol];
	
	//формируем конец подписи т.е. оставшиеся параметры 
	[sig appendFormat:@"v=3.0%@",_session.secret];
	
	//получаем хеш нашей строки
	NSString* _sig = [MD5 md5WithString:sig];
	
	//добовляем оставшиеся параметры для нашего запроса (полученный хеш и оставшиеся поля)
	[bodyString appendFormat:@"&fields=first_name,last_name,photo_medium&sig=%@&v=3.0&format=JSON&sid=%@",_sig,_session.sid];
	
	//формируем запрос серверу на основе нашего тела запроса (body string)
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	
	//посылаем серверу синхронный запрос
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	
	//переделываем полученный ответ в строку
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	//NSLog(@"%@",jsonString);
	
	//проверяем не содержится ли в ответе слово error (далее расширим обработку ошибок)
	NSRange errorTest = [jsonString rangeOfString:@"error"];
	if (errorTest.location != NSNotFound) {
		NSLog(@"VKApi: getProfileForUid error: %@",jsonString);
		return nil;
	} else {
		
		//если все нормально то разбираем строку
		SBJsonParser* parser = [[SBJsonParser alloc] init];
		
		//получаем наш словарь 
		NSDictionary *response = [parser objectWithString:jsonString];
		[parser release];
		
		//поскольку ответом сервера является массив словарей, получаем этот массив (смотри VK апи)
		NSArray *arrayOfRespons = [response objectForKey:@"response"];
		
		//создаем массив в который будет складываеть полученные анкеты
		NSMutableArray* users = [[NSMutableArray alloc] init];
		
		//перебераем все словари из массива словарей который прислал нам сервер
		for (NSDictionary *dict in arrayOfRespons) {
			
			//cоздаем обьет типа User и заполняем его параметры (разбираем словарь) 
			User* newUser = [[User alloc] init];
			newUser.uid = [[dict objectForKey:@"uid"] longLongValue];
			newUser.firstName = [dict objectForKey:@"first_name"];
			newUser.lastName = [dict objectForKey:@"last_name"];
			newUser.urlToPhoto = [dict objectForKey:@"photo_medium"];
			[users addObject:newUser];
		}
		return users;
	}
}

#pragma mark Messages methods
/* Отправка сообщения message пользователь с указанным uid */
-(int)sendMessage:(NSString *)message toUid:(long)uid {
	
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmessage=%@method=messages.sendtype=1uid=%lldv=3.0%@",_session.mid,message,uid,_session.secret];
	sig = [MD5 md5WithString:sig];
	
	
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody:[[NSString stringWithFormat:@"api_id=1951595&method=messages.send&uid=%lld&type=1&message=%@&sig=%@&v=3.0&format=JSON&sid=%@",uid,message,sig,_session.sid] dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	
	NSRange testError = [jsonString rangeOfString:@"error"];
	if (testError.location == NSNotFound) {
		return 0;
	} else {
		return -1;
	}

	
}

#pragma mark Status methods
/* Установка статуса */
-(int)setStatus:(NSString*) status {
	
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmethod=status.settext=%@v=3.0%@",_session.mid,status,_session.secret];
	sig = [MD5 md5WithString:sig];
	
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody: [[NSString stringWithFormat:@"api_id=1951595&method=status.set&text=%@&sig=%@&v=3.0&format=JSON&sid=%@",status,sig,_session.sid] dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	
	NSLog(@"SEND STATUS: %@",jsonString);
	return 0;
}

/* Получение статуса для uid */
-(NSString*)getStatusForUid: (long) uid {
	
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmethod=status.getuid=%lldv=3.0%@",_session.mid,uid,_session.secret];
	sig = [MD5 md5WithString:sig];
	
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody: [[NSString stringWithFormat:@"api_id=1951595&method=status.get&sig=%@&uid=%lld&v=3.0&format=JSON&sid=%@",sig,uid,_session.sid] dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	NSRange testError = [jsonString rangeOfString:@"error"];
	if (testError.location != NSNotFound) {
		NSLog(@"getStatus for uid error");
		return nil;
	}
	else {
		SBJsonParser* parser = [[SBJsonParser alloc] init];
		NSDictionary* response = [parser objectWithString:jsonString];
		[parser release];
		NSDictionary* dict = [response objectForKey:@"response"];
		NSString* status = [dict objectForKey:@"text"];
		return status;
	}
}

#pragma mark Long Poll Server Methods
/* Получение параметров необходимых для работы с Poll Long Server*/
-(void)getPollServerSession {
	NSString *sig = [NSString stringWithFormat:@"%dapi_id=1951595format=JSONmethod=messages.getLongPollServerv=3.0%@",_session.mid,_session.secret];
	sig = [MD5 md5WithString:sig];
	
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiServer]];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody: [[NSString stringWithFormat:@"api_id=1951595&method=messages.getLongPollServer&sig=%@&v=3.0&format=JSON&sid=%@",sig,_session.sid] dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSError* err = nil;
	NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
	NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	
	NSRange testError = [jsonString rangeOfString:@"error"];
	if(testError.location == NSNotFound) {
	
		SBJsonParser *parser = [[SBJsonParser alloc] init];
		NSDictionary *response = [parser objectWithString:jsonString];
		[parser release];
		NSDictionary *dict = [response objectForKey:@"response"];
		_pollSession.key = [dict objectForKey:@"key"];
		_pollSession.server = [dict objectForKey:@"server"];
		_pollSession.ts = [[dict objectForKey:@"ts"] longLongValue];
		_pollSession.isPollInit = YES;
	
		NSLog(@"%@ %@ %lld",_pollSession.key, _pollSession.server, _pollSession.ts);
	} else {
		NSLog(@"VKApi: getPollServerSession error: %@",jsonString);
	}
}

/* запуск фонового потока опрашивающего переодически сервер */
-(void)startPollServer {
	if (_pollSession.isPollInit == YES)
		[self performSelectorInBackground:@selector(startAsyncPollServer) withObject:nil];
	else {
		NSLog(@"PollSession isn't init");
	}

}

/* опрашивает в фоне LongPollServer на предмет обновлений */
-(void)startAsyncPollServer {
	while (1) {
		NSString* urlString = [NSString stringWithFormat:@"http://%@",_pollSession.server];
		NSURL* url = [[NSURL alloc] initWithString:urlString];
		NSString* body = [[NSString stringWithFormat:@"act=a_check&key=%@&ts=%lld&wait=25",_pollSession.key, _pollSession.ts] retain];
		NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
		[request setURL:url];
		[request setHTTPMethod:@"POST"];
		[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];

		NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
		NSString* jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
		
		NSRange errorTest = [jsonString rangeOfString:@"failed"];
		if (errorTest.location == NSNotFound) {
		
			SBJsonParser* parser = [[SBJsonParser alloc]init];
			NSDictionary* response = [parser objectWithString:jsonString];
			_pollSession.ts = [[response objectForKey:@"ts"] longLongValue];
		
			NSArray *updates = [response objectForKey:@"updates"];
			
			[self translateUpdates:updates];
			
		} else {
			//если сервер сообщил об истечении срока действия ключа то запрашиваем новую сессию
			NSLog(@"Poll Server Time out");
			[self getPollServerSession];
		}

	}
	
}

/* переводит обновления полученные от сервера и передает их соответствующим делегатам */
-(void)translateUpdates:(NSArray*) updates {
	for	(NSArray* update in updates){
		switch ([[update objectAtIndex:0] intValue]) {
				//4 - обновления связанные с сообщениями
			case 4: {
				if ([[update objectAtIndex:2] intValue] != 19) { //не учитываем исходящие сообщение из чата 1+2+16
					NSString* message = [update objectAtIndex:6];
					long uid = [[update objectAtIndex:3] longLongValue];
					[_receiverMessagesDelegate didReceiveMessage:message fromUid:uid];
				}
				break;
			}
				//user online
			case 8: {
				long uid = - [[update objectAtIndex:1] longLongValue];
				[_rosterDelegate didFriendOnlineWithUid:uid];
				break;
			}
				//user offline
			case 9:{
				long uid = - [[update objectAtIndex:1] longLongValue];
				[_rosterDelegate didFriendOfflineWithUid:uid];
				break;
			}
			default:
				break;
		}
	}
}
@end
